package org.modelcc.io.java.checker;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;

import org.modelcc.io.java.JavaModelReader;
import org.modelcc.io.java.JavaModelChecker;
import org.modelcc.io.java.JavaLanguageMetadata;
import org.modelcc.io.java.JavaLanguageClass;

/**
 * Checks for cyclic precedences
 */
public class PrecedenceChecker extends JavaModelChecker<JavaLanguageMetadata> 
{	
	public PrecedenceChecker (JavaModelReader reader)
	{
		super(reader);
	}
	
	@Override
	public void check(JavaLanguageMetadata metadata) 
	{
    	Set<JavaLanguageClass> pool = new HashSet<JavaLanguageClass>();
    	pool.addAll(metadata.getJavaElements());

    	// Token specifications preceded by any token specification in the pool.
    	Set<JavaLanguageClass> precededs;

    	Iterator<JavaLanguageClass> ite;
    	Iterator<JavaLanguageClass> ite2;
    	JavaLanguageClass ts;
    	JavaLanguageClass ts2;
    	Set<JavaLanguageClass> pset;

    	boolean found;

    	// Generate specification

    	while (!pool.isEmpty()) {

    		found = false;

    		// Update precededs list.
    		precededs = new HashSet<JavaLanguageClass>();
    		for (ite = pool.iterator();ite.hasNext();) {
    			ts = ite.next();
    			pset = metadata.prePrecedences.get(ts);
    			if (pset != null) {
    				precededs.addAll(pset);
    			}
    		}

    		// Add new unprecededs.
    		for (ite = pool.iterator();ite.hasNext();) {
    			ts = ite.next();
    			if (!precededs.contains(ts)) {
    				ite.remove();
    				found = true;
    			}
    		}

    		if (!found) {
    			String list = new String();
    			for (ite = pool.iterator();ite.hasNext();)
    				list += " "+ite.next().getElementClass().getCanonicalName();
    			log(Level.SEVERE, "Cyclic precedence exception:{0}.", new Object[]{list.toString()});
    			for (ite = pool.iterator();ite.hasNext();) {
    				ts = ite.next();
    				pset = metadata.prePrecedences.get(ts);
    				if (pset != null) {
    					for (ite2 = pool.iterator();ite2.hasNext();) {
    						ts2 = ite2.next();
    						pset.remove(ts2);
    					}
    					if (pset.isEmpty())
    						metadata.prePrecedences.remove(ts);
    				}
    			}
    			return;
    		}
    	}
    }

}
